lib: RepoCheckoutAtOptions
authorFelix Krull <f_krull@gmx.de>
Sun, 26 May 2019 17:18:12 +0000 (19:18 +0200)
committerColin Walters <walters@verbum.org>
Fri, 6 May 2022 16:53:54 +0000 (12:53 -0400)
rust-bindings/rust/Cargo.toml
rust-bindings/rust/conf/ostree.toml
rust-bindings/rust/src/auto/repo.rs
rust-bindings/rust/src/lib.rs
rust-bindings/rust/src/repo_checkout_at_options.rs [new file with mode: 0644]
rust-bindings/rust/tests/repo.rs
rust-bindings/rust/tests/util/mod.rs

index e0ad1322c175cf553bb9cc45755361a90be63e5d..3eac8eb4c7f01e00b909521fe6436906e105d1bf 100644 (file)
@@ -41,6 +41,7 @@ ostree-sys = { version = "0.3.0", path = "sys" }
 
 [dev-dependencies]
 maplit = "1.0.1"
+openat = "0.1.17"
 tempfile = "3"
 
 [features]
index 5d7e8331590249a52331e5a95aea2c1ec1312554..235cfbe1c75084386653f39d351e662f0a5e6747 100644 (file)
@@ -49,7 +49,6 @@ generate = [
 
     #"OSTree.RepoPruneOptions",
     #"OSTree.RepoExportArchiveOptions",
-    #"OSTree.RepoCheckoutAtOptions",
 ]
 
 manual = [
@@ -63,6 +62,8 @@ manual = [
     "GLib.KeyFile",
     "GLib.String",
     "GLib.Variant",
+
+    "OSTree.RepoCheckoutAtOptions",
 ]
 
 [crate_name_overrides]
@@ -94,6 +95,16 @@ status = "generate"
     name = "checkout_tree_at"
     ignore = true
 
+    [[object.function]]
+    # TODO: see which of these annotations I can upstream
+    name = "checkout_at"
+    [[object.function.parameter]]
+    name = "options"
+    const = true
+    [[object.function.parameter]]
+    name = "destination_path"
+    string_type = "filename"
+
 [[object]]
 name = "OSTree.RepoFinderResult"
 status = "generate"
index d7841c8ea7ae8a7e8abfda95c46f2a67b4b3944c..7e942f8c3708cceed27610ce96dad938662babee 100644 (file)
@@ -11,6 +11,8 @@ use MutableTree;
 use ObjectType;
 #[cfg(any(feature = "v2018_6", feature = "dox"))]
 use Remote;
+#[cfg(any(feature = "v2016_8", feature = "dox"))]
+use RepoCheckoutAtOptions;
 use RepoCheckoutMode;
 use RepoCheckoutOverwriteMode;
 use RepoCommitModifier;
@@ -39,6 +41,7 @@ use glib_sys;
 use gobject_sys;
 use libc;
 use ostree_sys;
+use std;
 use std::boxed::Box as Box_;
 use std::fmt;
 use std::mem;
@@ -96,10 +99,14 @@ impl Repo {
         }
     }
 
-    //#[cfg(any(feature = "v2016_8", feature = "dox"))]
-    //pub fn checkout_at<P: IsA<gio::Cancellable>>(&self, options: /*Ignored*/Option<&mut RepoCheckoutAtOptions>, destination_dfd: i32, destination_path: &str, commit: &str, cancellable: Option<&P>) -> Result<(), Error> {
-    //    unsafe { TODO: call ostree_sys:ostree_repo_checkout_at() }
-    //}
+    #[cfg(any(feature = "v2016_8", feature = "dox"))]
+    pub fn checkout_at<P: AsRef<std::path::Path>, Q: IsA<gio::Cancellable>>(&self, options: Option<&RepoCheckoutAtOptions>, destination_dfd: i32, destination_path: P, commit: &str, cancellable: Option<&Q>) -> Result<(), Error> {
+        unsafe {
+            let mut error = ptr::null_mut();
+            let _ = ostree_sys::ostree_repo_checkout_at(self.to_glib_none().0, mut_override(options.to_glib_none().0), destination_dfd, destination_path.as_ref().to_glib_none().0, commit.to_glib_none().0, cancellable.map(|p| p.as_ref()).to_glib_none().0, &mut error);
+            if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) }
+        }
+    }
 
     pub fn checkout_gc<P: IsA<gio::Cancellable>>(&self, cancellable: Option<&P>) -> Result<(), Error> {
         unsafe {
index d76538153766ad641f3bef53b2d353a6322f1ec7..ea3130f63cdea0bf8930101308a54ea86fa8e3b6 100644 (file)
@@ -34,10 +34,12 @@ pub use crate::auto::*;
 mod collection_ref;
 mod object_name;
 mod repo;
+mod repo_checkout_at_options;
 #[cfg(any(feature = "v2018_6", feature = "dox"))]
 pub use crate::collection_ref::*;
 pub use crate::object_name::*;
 pub use crate::repo::*;
+pub use crate::repo_checkout_at_options::*;
 
 // tests
 #[cfg(test)]
diff --git a/rust-bindings/rust/src/repo_checkout_at_options.rs b/rust-bindings/rust/src/repo_checkout_at_options.rs
new file mode 100644 (file)
index 0000000..0607af9
--- /dev/null
@@ -0,0 +1,167 @@
+use glib::translate::{Stash, ToGlib, ToGlibPtr};
+use ostree_sys::OstreeRepoCheckoutAtOptions;
+use std::os::raw::c_char;
+use std::path::PathBuf;
+use {RepoCheckoutMode, RepoCheckoutOverwriteMode};
+use {RepoDevInoCache, SePolicy};
+
+#[derive(PartialEq, Eq, Hash, Debug, Clone)]
+pub struct RepoCheckoutAtOptions {
+    pub mode: RepoCheckoutMode,
+    pub overwrite_mode: RepoCheckoutOverwriteMode,
+    pub enable_uncompressed_cache: bool,
+    pub enable_fsync: bool,
+    pub process_whiteouts: bool,
+    pub no_copy_fallback: bool,
+    pub force_copy: bool,
+    pub bareuseronly_dirs: bool,
+    pub force_copy_zerosized: bool,
+    pub subpath: Option<PathBuf>,
+    pub devino_to_csum_cache: Option<RepoDevInoCache>,
+    // pub filter: OstreeRepoCheckoutFilter,
+    // pub filter_user_data: gpointer,
+    pub sepolicy: Option<SePolicy>,
+    pub sepolicy_prefix: Option<String>,
+}
+
+impl Default for RepoCheckoutAtOptions {
+    fn default() -> Self {
+        RepoCheckoutAtOptions {
+            mode: RepoCheckoutMode::None,
+            overwrite_mode: RepoCheckoutOverwriteMode::None,
+            enable_uncompressed_cache: false,
+            enable_fsync: false,
+            process_whiteouts: false,
+            no_copy_fallback: false,
+            force_copy: false,
+            bareuseronly_dirs: false,
+            force_copy_zerosized: false,
+            subpath: None,
+            devino_to_csum_cache: None,
+            sepolicy: None,
+            sepolicy_prefix: None,
+        }
+    }
+}
+
+impl<'a> ToGlibPtr<'a, *const OstreeRepoCheckoutAtOptions> for RepoCheckoutAtOptions {
+    type Storage = (
+        Box<OstreeRepoCheckoutAtOptions>,
+        Stash<'a, *const c_char, Option<PathBuf>>,
+        Stash<'a, *const c_char, Option<String>>,
+    );
+
+    fn to_glib_none(&'a self) -> Stash<*const OstreeRepoCheckoutAtOptions, Self> {
+        let mut options = Box::new(unsafe { std::mem::zeroed::<OstreeRepoCheckoutAtOptions>() });
+        options.mode = self.mode.to_glib();
+        options.overwrite_mode = self.overwrite_mode.to_glib();
+        options.enable_uncompressed_cache = self.enable_uncompressed_cache.to_glib();
+        options.enable_fsync = self.enable_fsync.to_glib();
+        options.process_whiteouts = self.process_whiteouts.to_glib();
+        options.no_copy_fallback = self.no_copy_fallback.to_glib();
+        options.force_copy = self.force_copy.to_glib();
+        options.bareuseronly_dirs = self.bareuseronly_dirs.to_glib();
+        options.force_copy_zerosized = self.force_copy_zerosized.to_glib();
+        let subpath = self.subpath.to_glib_none();
+        options.subpath = subpath.0;
+        let sepolicy_prefix = self.sepolicy_prefix.to_glib_none();
+        options.sepolicy_prefix = sepolicy_prefix.0;
+
+        /*
+        devino_to_csum_cache: None,
+        sepolicy: None,
+        */
+
+        Stash(options.as_ref(), (options, subpath, sepolicy_prefix))
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use gio::{File, NONE_CANCELLABLE};
+    use glib_sys::{GFALSE, GTRUE};
+    use ostree_sys::{
+        OSTREE_REPO_CHECKOUT_MODE_NONE, OSTREE_REPO_CHECKOUT_MODE_USER,
+        OSTREE_REPO_CHECKOUT_OVERWRITE_NONE, OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL,
+    };
+    use std::ffi::{CStr, CString};
+    use std::ptr;
+
+    #[test]
+    fn should_convert_default_options() {
+        let options = RepoCheckoutAtOptions::default();
+        let stash = options.to_glib_none();
+        let ptr = stash.0;
+        unsafe {
+            assert_eq!((*ptr).mode, OSTREE_REPO_CHECKOUT_MODE_NONE);
+            assert_eq!((*ptr).overwrite_mode, OSTREE_REPO_CHECKOUT_OVERWRITE_NONE);
+            assert_eq!((*ptr).enable_uncompressed_cache, GFALSE);
+            assert_eq!((*ptr).enable_fsync, GFALSE);
+            assert_eq!((*ptr).process_whiteouts, GFALSE);
+            assert_eq!((*ptr).no_copy_fallback, GFALSE);
+            assert_eq!((*ptr).force_copy, GFALSE);
+            assert_eq!((*ptr).bareuseronly_dirs, GFALSE);
+            assert_eq!((*ptr).force_copy_zerosized, GFALSE);
+            assert_eq!((*ptr).unused_bools, [GFALSE; 4]);
+            assert_eq!((*ptr).subpath, ptr::null());
+            assert_eq!((*ptr).devino_to_csum_cache, ptr::null_mut());
+            assert_eq!((*ptr).unused_ints, [0; 6]);
+            assert_eq!((*ptr).unused_ptrs, [ptr::null_mut(); 3]);
+            assert_eq!((*ptr).filter, None);
+            assert_eq!((*ptr).filter_user_data, ptr::null_mut());
+            assert_eq!((*ptr).sepolicy, ptr::null_mut());
+            assert_eq!((*ptr).sepolicy_prefix, ptr::null());
+        }
+    }
+
+    #[test]
+    fn should_convert_non_default_options() {
+        let options = RepoCheckoutAtOptions {
+            mode: RepoCheckoutMode::User,
+            overwrite_mode: RepoCheckoutOverwriteMode::UnionIdentical,
+            enable_uncompressed_cache: true,
+            enable_fsync: true,
+            process_whiteouts: true,
+            no_copy_fallback: true,
+            force_copy: true,
+            bareuseronly_dirs: true,
+            force_copy_zerosized: true,
+            subpath: Some("sub/path".into()),
+            devino_to_csum_cache: Some(RepoDevInoCache::new()),
+            sepolicy: Some(SePolicy::new(&File::new_for_path("a/b"), NONE_CANCELLABLE).unwrap()),
+            sepolicy_prefix: Some("prefix".into()),
+        };
+        let stash = options.to_glib_none();
+        let ptr = stash.0;
+        unsafe {
+            assert_eq!((*ptr).mode, OSTREE_REPO_CHECKOUT_MODE_USER);
+            assert_eq!(
+                (*ptr).overwrite_mode,
+                OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL
+            );
+            assert_eq!((*ptr).enable_uncompressed_cache, GTRUE);
+            assert_eq!((*ptr).enable_fsync, GTRUE);
+            assert_eq!((*ptr).process_whiteouts, GTRUE);
+            assert_eq!((*ptr).no_copy_fallback, GTRUE);
+            assert_eq!((*ptr).force_copy, GTRUE);
+            assert_eq!((*ptr).bareuseronly_dirs, GTRUE);
+            assert_eq!((*ptr).force_copy_zerosized, GTRUE);
+            assert_eq!((*ptr).unused_bools, [GFALSE; 4]);
+            assert_eq!(
+                CStr::from_ptr((*ptr).subpath),
+                CString::new("sub/path").unwrap().as_c_str()
+            );
+            assert_ne!((*ptr).devino_to_csum_cache, ptr::null_mut());
+            assert_eq!((*ptr).unused_ints, [0; 6]);
+            assert_eq!((*ptr).unused_ptrs, [ptr::null_mut(); 3]);
+            assert_eq!((*ptr).filter, None);
+            assert_eq!((*ptr).filter_user_data, ptr::null_mut());
+            assert_ne!((*ptr).sepolicy, ptr::null_mut());
+            assert_eq!(
+                CStr::from_ptr((*ptr).sepolicy_prefix),
+                CString::new("prefix").unwrap().as_c_str()
+            );
+        }
+    }
+}
index 7f8a7d119f63984c04bc0a32ba0d40313c6cadf9..02a094e4f382136df359347c4595971499a6ada8 100644 (file)
@@ -1,5 +1,6 @@
 extern crate gio;
 extern crate glib;
+extern crate openat;
 extern crate ostree;
 extern crate tempfile;
 #[macro_use]
@@ -11,7 +12,10 @@ use util::*;
 use gio::prelude::*;
 use gio::NONE_CANCELLABLE;
 use glib::prelude::*;
-use ostree::{ObjectName, ObjectType};
+use ostree::{
+    ObjectName, ObjectType, RepoCheckoutAtOptions, RepoCheckoutMode, RepoCheckoutOverwriteMode,
+};
+use std::os::unix::io::AsRawFd;
 
 #[test]
 fn should_commit_content_to_repo_and_list_refs_again() {
@@ -91,11 +95,51 @@ fn should_checkout_tree() {
         )
         .expect("checkout tree");
 
-    let testfile_path = checkout_dir
-        .path()
-        .join("test-checkout")
-        .join("testdir")
-        .join("testfile");
-    let testfile_contents = std::fs::read_to_string(testfile_path).expect("test file");
-    assert_eq!("test\n", testfile_contents);
+    assert_test_file(checkout_dir.path());
+}
+
+#[test]
+fn should_checkout_at_with_none_options() {
+    let test_repo = TestRepo::new();
+    let checksum = test_repo.test_commit("test");
+    let checkout_dir = tempfile::tempdir().expect("checkout dir");
+
+    let dirfd = openat::Dir::open(checkout_dir.path()).expect("openat");
+    test_repo
+        .repo
+        .checkout_at(
+            None,
+            dirfd.as_raw_fd(),
+            "test-checkout",
+            &checksum,
+            NONE_CANCELLABLE,
+        )
+        .expect("checkout at");
+
+    assert_test_file(checkout_dir.path());
+}
+
+#[test]
+fn should_checkout_at_with_options() {
+    let test_repo = TestRepo::new();
+    let checksum = test_repo.test_commit("test");
+    let checkout_dir = tempfile::tempdir().expect("checkout dir");
+
+    let dirfd = openat::Dir::open(checkout_dir.path()).expect("openat");
+    test_repo
+        .repo
+        .checkout_at(
+            Some(&RepoCheckoutAtOptions {
+                mode: RepoCheckoutMode::User,
+                overwrite_mode: RepoCheckoutOverwriteMode::UnionIdentical,
+                ..Default::default()
+            }),
+            dirfd.as_raw_fd(),
+            "test-checkout",
+            &checksum,
+            NONE_CANCELLABLE,
+        )
+        .expect("checkout at");
+
+    assert_test_file(checkout_dir.path());
 }
index 8d92ea8ae5347035d2fa0c93a513512511948df3..32ed812c2b7fef8d815b2581c9ca8226da02bfb7 100644 (file)
@@ -64,3 +64,12 @@ pub fn commit(repo: &ostree::Repo, mtree: &ostree::MutableTree, ref_: &str) -> G
         .expect("commit transaction");
     checksum
 }
+
+pub fn assert_test_file(checkout: &Path) {
+    let testfile_path = checkout
+        .join("test-checkout")
+        .join("testdir")
+        .join("testfile");
+    let testfile_contents = std::fs::read_to_string(testfile_path).expect("test file");
+    assert_eq!("test\n", testfile_contents);
+}